'''
Created on 2018年1月13日

@author: heguofeng
'''

import hashlib
import unittest
from src.file_folder import FolderInfo, FileInfo, FolderWidgets

from src.filefolder import FileInfo,FolderInfo
import os
from tkinter.ttk import Button

DUPLICATION_MODE_SIZETIME = 1
DUPLICATION_MODE_SIZETYPEHASH = 2


class FileUnDuplicator(object):
    '''
    to find Duplicate files
    
    '''

    def __init__(self, paths, mode= DUPLICATION_MODE_SIZETIME):
        '''
        Constructor
        paths = [path1,path2,path3,...]
        file_dict = {(size,mtime):[fileinfo,fileinfo...]}
        '''
        self.paths = paths
        self.file_dict = {}
        self.mode = mode
        print(self.mode)
        self.folders_dict = {}
        self.load()
        
    def set_mode(self, mode):
        self.mode = mode
        
    def load(self):
        for path in self.paths:
            self.folders_dict[path] = FolderInfo(path, "")
            self.load_files(self.folders_dict[path])

        pass
    
    def load_files(self, folder_info):
        for n in folder_info.nodes:
            node = folder_info.nodes[n]
            if isinstance(node, FileInfo):
                if self.mode == DUPLICATION_MODE_SIZETIME:
                    if ("sm", node.size, node.mtime) in self.file_dict.keys():
                        self.file_dict[("sm", node.size, node.mtime)].append(node)
                    else:
                        self.file_dict[("sm", node.size, node.mtime)] = [node]
                if self.mode == DUPLICATION_MODE_SIZETYPEHASH:
                    filetype = node.name.split(".")[-1]
                    if ("st", node.size, filetype) in self.file_dict.keys():
                        self.file_dict[("st", node.size, filetype)].append(node)
                    else:
                        self.file_dict[("st", node.size, filetype)] = [node]
            else:  # folder
                self.load_files(node)
        pass
    
    def calcSha1(self, filepath):
        maxbuf = 8192
        sha1obj = hashlib.sha1()
        try: # skip some imreadable file
            with open(filepath, 'rb') as f:
                while True:
                    buf = f.read(maxbuf)
                    if not buf:
                        f.close()
                        break
                    sha1obj.update(buf)
        except:
            return 0
        hash = sha1obj.hexdigest()
        return hash
    
    def calcMD5(self, filepath):
        with open(filepath, 'rb') as f:
            md5obj = hashlib.md5()
            md5obj.update(f.read())
            hash = md5obj.hexdigest()
        return hash
    
    def getHashDuplication(self, fileinfolist):
        hashDict = {}
        for fi in fileinfolist:
            hash = self.calcSha1(os.path.join(fi.path, fi.name))
            if hash in hashDict:
                hashDict[hash].append(fi)
            else:
                hashDict[hash] = [fi]
        return hashDict
        pass
    
    def find_duplication(self):
        dup_files = {}
        for f in self.file_dict:
            if f[0] == "sm":
                if len(self.file_dict[f]) > 1:
                    dup_files[f] = self.file_dict[f]
            if f[0] == "st":
                if len(self.file_dict[f]) > 1:
                    hashfile = self.getHashDuplication(self.file_dict[f])
                    for hf in hashfile:
                        if len(hashfile[hf]) > 1:
                            dup_files[f + (hf,)] = hashfile[hf]
        return dup_files
    
    def turnToFolderInfo(self, dupFiles):
        folderInfo = FolderInfo("", "")
        for f in dupFiles:
            tempname = ""
            for item in f:
                tempname += "_" + str(item)
            subFolderInfo = FolderInfo("", "")
            for fi in dupFiles[f]:
                subFolderInfo.add("", tempname, fi)
            folderInfo.add("", tempname, subFolderInfo)

        return folderInfo

            
class DuplicateWidgets(FolderWidgets):
    '''
    widgets has directory label,directory entry,open file dialog button and directory view
    also has popupmenu 
    select event 
    use following config:
        DuplicationMode :  1  # 
    '''

    def __init__(self, master=None, show_full_path=True, config={}):
        self.config = config
        super().__init__(master, \
                         show_full_path=self.config.get("show_full_path", True), folder_label="文件夹")
        self.folderPath.set(self.config.get("last_folder_path", "."))
        
    def createWidgets(self):

        super().createWidgets()
        self.select1stButton = Button(self, text="选择第一个", command=self.select1st)
        self.select2ndtButton = Button(self, text="选择第二个后", command=self.select2nd)
        
        self.select1stButton.grid(row=17, column=8)
        self.select2ndtButton.grid(row=17, column=9)
        
#         self.dirTreeview.grid(row=1, column=0, rowspan=16, columnspan=10, sticky=E + W)
#         self.dirScrollbar.grid(row=1, column=10, rowspan=16, sticky=N + S + E)
        
        self.dupButton = Button(self, text="查找重复", command=self.doFindDuplication)
        self.dupButton.grid(row=0, column=9)

    def doFindDuplication(self):
        # folderInfo = FolderInfo(self.srcFolderWidgets.folderPath.get(),"")
        fud = FileUnDuplicator([self.folderPath.get()], mode=self.config.get("DuplicationMode", DUPLICATION_MODE_SIZETIME))
        self.config["last_folder_path"] = self.folderPath.get()
        self.statusLabel.config(text="Start to find duplication files...")
        folderInfo = fud.turnToFolderInfo(fud.find_duplication())
        count = folderInfo.count()
        self.statusLabel.config(text="End of finding. %d directory %d files %d totalsize!" % (count[0], count[1], count[2]))
        self.refreshTreeview(folderInfo)
        
        pass
        
    def select1st(self):
        children = self.dirTreeview.get_children()
        firstGrandsons = []
        for child in children:
            if len(self.dirTreeview.get_children(child)):
                firstGrandsons.append(self.dirTreeview.get_children(child)[0])
        self.dirTreeview.selection_set(firstGrandsons)
        pass
    
    def select2nd(self):
        children = self.dirTreeview.get_children()
        secondGrandsons = []
        for child in children:
            if len(self.dirTreeview.get_children(child)) > 1:
                secondGrandsons.extend(self.dirTreeview.get_children(child)[1:])
        self.dirTreeview.selection_set(secondGrandsons)        
        pass


class DupTest(unittest.TestCase):

    def setUp(self):
        pass

    def tearDown(self):
        pass

    def testDup(self):
        fd = FileUnDuplicator(["/home/heguofeng/test/", "/home/heguofeng/bak/"])
        dup_files = fd.find_duplication()
        print(len(dup_files))
        for f in dup_files:
            print("%s:%s" % (f, dup_files[f]))
            print(dup_files[f][0])
        assert(len(dup_files) == 1)
        pass


if __name__ == "__main__":
    # import sys;sys.argv = ['', 'Test.testName']
    unittest.main()
        
